package com.nts.bupna.generator;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

import com.nts.bupna.BupnaException;
import com.nts.bupna.errors.CompilerError;
import com.nts.bupna.errors.ConsoleReporter;
import com.nts.bupna.errors.Reporter;

public class JavaToClass {
    private final Reporter reporter;
    private final JavaCompiler compiler;

    public JavaToClass() {
        this(new ConsoleReporter());
    }

    public JavaToClass(final Reporter errorReporter) {
        this(errorReporter, ToolProvider.getSystemJavaCompiler());
    }

    public JavaToClass(final Reporter errorReporter, final JavaCompiler compiler) {
        this.reporter = errorReporter;
        this.compiler = compiler;
    }

    public void compile(final String name, final String code, final String outputLocation) throws IOException {
        final JavaSourceFromString javaSource = new JavaSourceFromString(name, code);
        callCompiler(javaSource, outputLocation);
        if (reporter.hasErrors()) {
            throw new BupnaException("Error compiling java code");
        }
    }

    private void callCompiler(final JavaFileObject c, final String outputLocation) throws IOException {
        final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
        final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
        fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(outputLocation)));
        final Iterable<? extends JavaFileObject> compilationUnit = Arrays.asList(c);
        final CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnit);
        task.call();

        for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
            final CompilerError error = new CompilerError(diagnostic);
            reporter.reportError(error);
        }

        fileManager.close();
    }
}
